package com.it.flowable.listener;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BoundaryEvent;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.ExtensionElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.job.service.impl.persistence.entity.JobEntity;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class AdvancedFlowableListener extends AbstractFlowableEngineEventListener {
    @Lazy
    @Resource
    private RepositoryService repositoryService;
    // @Lazy懒加载  方案 1：构造器注入 + 接口隔离（最佳实践）;  方案 2：配置类显式控制（适合简单项目）
    @Lazy
    @Resource
    private RuntimeService runtimeService;
    @Lazy
    @Resource
    private TaskService taskService;
    @Lazy
    @Resource
    private HistoryService historyService;

    // 触发待办消息
    @Override
    protected void taskCreated(FlowableEngineEntityEvent event) {
        log.info("[taskCreated] {}", event.getEntity().getClass().getName());
        TaskEntity task = (TaskEntity) event.getEntity();
        if (task.getAssignee() == null) {
            handelNotification(task, MessageType.PENDING.name());
        }
    }

    // 触发完成消息
    @Override
    protected void taskCompleted(FlowableEngineEntityEvent event) {
        log.info("[taskCompleted] {}", event.getEntity().getClass().getName());
        handelNotification((TaskEntity) event.getEntity(), MessageType.COMPLETE.name());
    }

    // 触发 转交消息
    @Override
    protected void taskAssigned(FlowableEngineEntityEvent event) {
        log.info("[taskAssigned] {}", event.getEntity().getClass().getName());
        // 判断是初始分配还是转交
        TaskEntity entity = (TaskEntity) event.getEntity();
        if (isInitialAssignment(entity)) {
            handelNotification(entity, MessageType.PENDING.name()); // 初始分配
        } else {
            handelNotification(entity, MessageType.TRANSFER.name()); // 任务转交
        }
    }

    // 判断是否是初始分配
    private boolean isInitialAssignment(TaskEntity task) {
        // 通过查询任务历史来判断是否是第一次分配
        HistoricTaskInstance historicTask = historyService.createHistoricTaskInstanceQuery()
                .taskId(task.getId())
                .singleResult();

        // 如果没有历史记录或者历史记录中的办理人与当前不同，则是转交
        if (historicTask == null) {
            return true;
        }
        return historicTask.getAssignee() == null ||
                historicTask.getAssignee().equals(task.getAssignee());
    }
    // 超时消息
    @Override
    protected void timerFired(FlowableEngineEntityEvent event) {
        log.info("[timerFired] {}", event.getEntity().getClass().getName());
        // 超时消息处理
        if (event.getEntity() instanceof JobEntity) {
            JobEntity job = (JobEntity) event.getEntity();
            // 获取定时器对应的用户任务信息
            String activityId = job.getJobHandlerConfiguration(); // 这里包含用户任务ID
            String boundaryEventId = JSON.parseObject(activityId, JSONObject.class).getString("activityId");
            BpmnModel bpmnModel = repositoryService.getBpmnModel(job.getProcessDefinitionId());
            BoundaryEvent boundaryEvent = (BoundaryEvent) bpmnModel.getFlowElement(boundaryEventId);
            String userTaskId = boundaryEvent.getAttachedToRefId();  // 获取关联的用户任务ID

            // 通过流程实例ID获取当前任务信息
            String processInstanceId = job.getProcessInstanceId();
            if (processInstanceId == null) {
                return;
            }
            // 获取流程实例中的当前任务
            TaskEntity task = (TaskEntity) taskService.createTaskQuery()
                    .processInstanceId(processInstanceId)
                    .taskDefinitionKey(userTaskId)
                    .singleResult();
            log.info("超时任务: {}, 负责人: {}, 创建时间: {}", task.getName(), task.getAssignee(), task.getCreateTime());
            handelNotification(task, MessageType.TIMEOUT.name());
        }
    }

    // 催办消息
    protected void remind(FlowableEngineEntityEvent event) {

    }

    private void handelNotification(TaskEntity taskEntity, String notifyType) {
        log.info("[getByBpmXmlElement] {}", "开始");

        // 1. 获取BPMN模型和用户任务
        BpmnModel bpmnModel = repositoryService.getBpmnModel(taskEntity.getProcessDefinitionId());
        UserTask userTask = (UserTask) bpmnModel.getFlowElement(taskEntity.getTaskDefinitionKey());
        // 2. 获取扩展属性
        Map<String, List<ExtensionElement>> extensions = userTask.getExtensionElements();
        List<ExtensionElement> elementList = extensions.get("notify");
        if (elementList == null || elementList.isEmpty()) {
            return;
        }

        // 3. 解析通知配置
        List<NotifyEntity> list = elementList.stream().map(extensionElement -> {
            NotifyEntity entity = new NotifyEntity();
            entity.setNotifyType(extensionElement.getAttributeValue(null, "notifyType"));
            entity.setTemplateId(extensionElement.getAttributeValue(null, "templateId"));
            return entity;
        }).collect(Collectors.toList());

        log.info("[getByBpmXmlElement] 解析到的通知配置: {}", JSON.toJSONString(list));

        // 4. 查找匹配的通知类型并发送消息
        list.stream()
                .filter(entity -> notifyType.equals(entity.getNotifyType()))
                .findFirst()
                .ifPresent(matchedEntity -> {
                    String template = "**${processName}审批** • 编号：${businessKey}\n\n" +
                            "流程类型：${notifyTypeName}\n" +
                            "任务节点：${taskName}\n" +
                            "发起时间：${startTime}\n\n" +
                            "请及时处理此审批单";// 🚀 [立即审批](${approvalLink})

                    // 构建模板变量数据
                    HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                            .processInstanceId(taskEntity.getProcessInstanceId())
                            .singleResult();
                    Map<String, Object> data = new HashMap<>();
                    data.put("processName", historicProcessInstance.getProcessDefinitionName());
                    data.put("businessKey", historicProcessInstance.getBusinessKey());
                    data.put("notifyType", notifyType);
                    data.put("notifyTypeName", MessageType.valueOf(notifyType).getDescription());
                    data.put("taskName", taskEntity.getName());
                    data.put("startTime", taskEntity.getCreateTime()); // 需要根据实际情况获取
                    data.put("processInstanceId", taskEntity.getProcessInstanceId());
                    data.put("taskId", taskEntity.getId());
                    data.put("assignee", taskEntity.getAssignee()); // 直接获取分配人ID

                    // 发送消息
                    Map<String, Object> message = new HashMap<>();
                    message.put("template", template);
                    message.put("data", data);
                    log.info("[发送消息-{} - {}-{}] {}", taskEntity.getAssignee(), notifyType, taskEntity.getName(), JSON.toJSONString(message));
                    // 实际发送消息的方法
                    // 实现具体的消息发送逻辑，发送到消息队列
                });
    }

    /**
     * 从流程变量中获取通知配置（保持与XML配置相同的数据结构）
     */
    private void getByBpmVariable(TaskEntity taskEntity) {
        log.info("[getByBpmVariable] 开始读取流程变量配置");

        // 1. 从流程变量中获取配置（变量名约定为notify）
        Object variableValue = runtimeService.getVariable(taskEntity.getExecutionId(), "notify");

        // 2. 类型转换校验
        if (!(variableValue instanceof List)) {
            log.warn("[getByBpmVariable] 流程变量格式错误，预期为List类型");
            return;
        }

        // 3. 转换为目标数据结构
        List<NotifyEntity> list = new ArrayList<>();
        try {
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> rawConfigs = (List<Map<String, Object>>) variableValue;

            rawConfigs.forEach(config -> {
                NotifyEntity entity = new NotifyEntity();
                entity.setNotifyType(String.valueOf(config.get("notifyType")));
                entity.setTemplateId(String.valueOf(config.get("templateId"))); // 修正：应该是setTemplateId
                list.add(entity);
            });
        } catch (Exception e) {
            log.error("[getByBpmVariable] 流程变量解析失败", e);
        }

        log.info("[getByBpmVariable] 读取结果: {}", JSON.toJSONString(list));
    }
    private void getByTable(TaskEntity taskEntity) {
        // tableService.lambdaQuery().eq()...
    }

    @Getter
    public enum MessageType {
        PENDING("待办消息"),
        COMPLETE("完成消息"),
        TRANSFER("转交消息"),
        TIMEOUT("超时消息"),
        REMIND("催办消息"),
        ;

        private final String description;

        MessageType(String description) {
            this.description = description;
        }


        public static List<Map<String, String>> getMap() {
            return Arrays.stream(AdvancedFlowableListener.MessageType.values())
                    .map(v1 -> {
                        HashMap<String, String> map = new HashMap<>();
                        map.put("notifyType", v1.name());
                        map.put("templateId", "templateId_" + v1.name());
                        return map;
                    }).collect(Collectors.toList());
        }

    }

    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public static class NotifyEntity {
        private String notifyType;
        private String templateId;
        // private String remark;
        // 更多属性
    }
}